export const draggable = (
    target,
    parent = document.body,
    options = {
        dragStart: null,
        dragEnd: null,
    },
) => {
    if (!(target instanceof HTMLElement) || !(parent instanceof HTMLElement)) {
        throw new Error(
            "target and parent must HTMLElement in mv cli plugin draggable...",
        );
    }

    // 判断是否开启了浮动
    const targetStyles = window.getComputedStyle(target);
    if (targetStyles.position !== "absolute") {
        throw new Error(
            "target element missing position absolute props in style",
        );
    }

    let offsetX, offsetY;

    const cleanEffect = () => {
        target.setAttribute("draggable", false);
        target.removeEventListener("dragstart", dragStart);
        parent.removeEventListener("dragover", dragMoving);
        parent.removeEventListener("drop", dragEnd);
    };

    const dragStart = (e) => {
        offsetX = e.clientX - target.getBoundingClientRect().left;
        offsetY = e.clientY - target.getBoundingClientRect().top;
        e.dataTransfer.setData("text/plain", "");
        if (typeof options.dragStart === "function") options.dragStart();
    };
    const dragMoving = (e) => e.preventDefault();
    const dragEnd = (e) => {
        e.preventDefault();
        let newX = e.clientX - offsetX;
        let newY = e.clientY - offsetY;
        const containerRect = parent.getBoundingClientRect();
        const draggableRect = target.getBoundingClientRect();
        newX = Math.max(
            containerRect.left,
            Math.min(newX, containerRect.right - draggableRect.width),
        );
        newY = Math.max(
            containerRect.top,
            Math.min(newY, containerRect.bottom - draggableRect.height),
        );
        target.style.left = `${newX - containerRect.left}px`;
        target.style.top = `${newY - containerRect.top}px`;
        if (typeof options.dragEnd === "function") options.dragEnd();
    };

    cleanEffect();
    target.setAttribute("draggable", true);
    target.addEventListener("dragstart", dragStart);
    parent.addEventListener("dragover", dragMoving);
    parent.addEventListener("drop", dragEnd);

    return cleanEffect;
};
